﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Serialization;
using SolverTemplateLib;

[assembly: TypeForwardedTo(typeof(SolverTemplateLib.BackTracker))]

namespace NewKataminoSolver
{
    // [Serializable] -> ISerializable
    [XmlRoot("Solution")]
    public class KataminoBackTracker : BackTracker, ISerializable
    {
        // static data, needed once
        private static Katamino form;
        private static Penta[][] Variations;

        // local data, for each partial solution
        private List<int> _pentaSet;

        [XmlArray]
        public List<int> _solSet;
        private List<int> _rotSet;
        private Board _b; // board contains its bitmap

        // parameterless constructor for XML serialization!?!
        public KataminoBackTracker() { }

        // create initial / empty / partial solution
        public KataminoBackTracker(Katamino k, int w, int h)
        {
            // set static data
            form = k;
            Variations = new Penta().Variations();

            // set and initialize data
            _pentaSet = new List<int>();
            _solSet = new List<int>();
            _rotSet = new List<int>();
            for (int i = 0; i < 12; i++) _pentaSet.Add(i); // some Range method!?!
            _b = new Board(w, h);
        }

        private KataminoBackTracker(Board b, List<int> pentaSet, List<int> solutionSet, List<int> rotationSet)
        {
            _b = b;
            _pentaSet = pentaSet;
            _solSet = solutionSet;
            _rotSet = rotationSet;
        }
        public override bool IsCancelled()
        {
            return form.KataminoBackgroundWorker().CancellationPending;
        }

        public override bool IsSolution()
        {
            return (_pentaSet.Count == 0);
        }
        public override void ProcessCandidate()
        {
        }
        public override void ProcessSolution()
        {
            Debug.Assert(form.InvokeRequired,
                "Threading Error",
                "For Katamino, this thread should not run on UI thread");

            // tell UI thread its progress and to draw and store solution
            form.UpdatePicture(_b.picture);
            form.KataminoBackgroundWorker().ReportProgress(_b.D[0,0] * 8, _b.picture);
        }
        public override List<BackTracker> Candidates()
        {
            List<BackTracker> result = new List<BackTracker>();

            // find first free field
            if (_b.firstFree())
            {
                // iterate through pentas
                foreach (int _p in _pentaSet)
                {
                    int rotation = 0;
                    List<int> pentaRem = new List<int>(_pentaSet); // only valid for value types
                    pentaRem.Remove(_p);
                    foreach (Penta _pt in Variations[_p])
                    {
                        // if _pt can be placed at first free field,
                        if (_b.pentaFree(_pt))
                        {
                            // we can add _pt to board and remove _p from list
                            List<int> solSet = new List<int>(_solSet);
                            List<int> rotSet = new List<int>(_rotSet);
                            solSet.Add(_p);
                            rotSet.Add(rotation);
                            // rotSet[_p] = rotation;
                            result.Add(new KataminoBackTracker(_b.Add(_pt, _p + 1), pentaRem, solSet, rotSet));
                        }
                        rotation++; // counter for rotation administration
                    }
                }
            }

            return result;
        }

        public void Finish()
        {
        }

        // The ISerializable interface: for serialization fill info
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("SolSet", this._solSet, _solSet.GetType());
            info.AddValue("RotSet", this._rotSet, _rotSet.GetType()); // success when not public ??
        }
        // For deserialization: define constructor that takes SerializationInfo and StreamingContext
        protected KataminoBackTracker(SerializationInfo info, StreamingContext context)
        {
            _solSet = (List<int>)info.GetValue("Solution", _solSet.GetType());
            _rotSet = (List<int>)info.GetValue("Solution", _rotSet.GetType());
        }
    }
}
